﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Comdiv.QWeb.Utils;

namespace Comdiv.QWeb.ViewEngine {
	public class QViewBindAttribute : Attribute {
		private const BindingFlags allattr = BindingFlags.NonPublic | BindingFlags.Public |
		                                     BindingFlags.Instance |
		                                     BindingFlags.SetProperty | BindingFlags.SetField
		                           ;

		public string Name { get; set; }
		public object Default { get; set; }
		public MemberInfo Member { get; set; }

		protected string getName() {
			return Name ?? Member.Name;
		}

		public virtual void Bind(IQView view, QViewContext context) {
			lock (this) {
				var isseted = false;
				if (context.AdvancedData != null) {
					if (context.AdvancedData is IDictionary<string, object>) {
						var d = context.AdvancedData as IDictionary<string, object>;
						if (d.ContainsKey(getName())) {
							Set(view, d[getName()]);
							isseted = true;
						}
					}
					else {
						var member = context.AdvancedData.GetType().GetMember(getName(), allattr).FirstOrDefault();
						if (null != member) {
							if (member is PropertyInfo) {
								Set(view, ((PropertyInfo) member).GetValue(context.AdvancedData, null));
							}
							else if (member is FieldInfo) {
								Set(view, ((FieldInfo) member).GetValue(context.AdvancedData));
							}
							isseted = true;
						}
					}
				}
				if (!isseted && context.ViewData != null) {
					var member =
						context.ViewData.GetType().GetMembers(allattr)
							.Where(x => x.Name == getName()).FirstOrDefault();
					if (null != member) {
						if (member is FieldInfo) {
							Set(view, ((FieldInfo) member).GetValue(context.ViewData));
						}
						else if (member is PropertyInfo) {
							Set(view, ((PropertyInfo) member).GetValue(context.ViewData, null));
						}
						isseted = true;
					}
				}

				if (!isseted) {
					bindToDefaults(view, context);
				}
			}
		}

		private void bindToDefaults(IQView view, QViewContext context) {
			if (context.Context != null && context.Context.Parameters.ContainsKey(getName().ToLower())) {
				Set(view, context.Context.Parameters[getName()]);
			}
			else {
				Set(view, Default);
			}
		}

		public void Set(object target, object value) {
			lock (this) {
				if (Member is FieldInfo) {
					((FieldInfo) Member).SetValue(target, value.to(((FieldInfo) Member).FieldType));
				}
				else if (Member is PropertyInfo) {
					((PropertyInfo) Member).SetValue(target, value.to(((PropertyInfo) Member).PropertyType), null);
				}
			}
		}
	}
}